package com.lsa.skienna.challenge.chap9.the110902_PlayingWithWheels;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import junit.framework.TestCase;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;

import com.lsa.helpers.Utils;
import com.lsa.skienna.challenge.chap9.the110902_PlayingWithWheels.Main.Task;
import com.lsa.skienna.challenge.chap9.the110902_PlayingWithWheels.Main.TaskReader;

public class Test_PlayingWithWheels extends TestCase {
    public void testWithExamples() throws Throwable {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        Main.process(new FileInputStream("data/pc9/playingWithWheels/110902.inp"), new PrintStream(out));
        String expected = FileUtils.readFileToString(new File("data/pc9/playingWithWheels/110902.oup"));
        expected = expected.replaceAll("\n", IOUtils.LINE_SEPARATOR);
        assertEquals(expected, out.toString());
    }
    
    public void test1() throws Throwable {
        compareTest("data/pc9/playingWithWheels/!test1.inp");
    }
    
    public void test3() throws Throwable {
        compareTest("data/pc9/playingWithWheels/!test3.inp");
    }
    
    public void test4() throws Throwable {
		compareTest("data/pc9/playingWithWheels/!test4.inp");
    }

	private void compareTest(String fileInput) throws FileNotFoundException {
		TaskReader taskReader = new TaskReader(new FileInputStream(fileInput));
        try {
            Task task = null;
            while((task = taskReader.nextTask()) != null){
                assertEquals(Main.solveBruteForce(task), Main.solveAStar(task));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
	}
    
    public void testWithRandom() throws Throwable {
        final int testCount = 30;
        final long start = System.nanoTime();
        long solvingTotal = 0;
        for (int i = 0; i < testCount; i++) {
            System.out.println("************************");
            System.out.println(String.format("************Performing test %s \n", i));
            long time = performRandomTest(i);
            solvingTotal += time;
            System.out.println("TIME:" + time);
            System.out.println("************************");
            System.out.println("************************");
            System.out.println();
        }
        System.out.println("Solving average:" + (((double)solvingTotal / (double)testCount * 1000000.0)));
        System.out.println("Solving total:" + (solvingTotal / 1000000.0));
        System.out.println("OVERALL TIME:" + ((System.nanoTime() - start) / 1000000.0));
    }

    public long performRandomTest(int testNumber) throws IOException,
            UnsupportedEncodingException, FileNotFoundException {
        long time = 0;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(out);
        
        ps.println("1");
        ps.println();
        
        int begin = Utils.random(1, 9999);
        int target = Utils.random(1, 9999);
        while (begin == target) {
            target = Utils.random(1, 9999);
        }
        
        Main.outputInteger(ps, begin);
        Main.outputInteger(ps, target);
        
        Set<Integer> forbiddenSet = new HashSet<Integer>(Arrays.asList(begin, target));
        final int FORBIDDEN_COUNT = Utils.random(7000, 8000);
        ps.println(FORBIDDEN_COUNT);
        for (int i = 0; i < FORBIDDEN_COUNT; i++) {
            int forbidden = Utils.random(1, 9999);
            while (forbiddenSet.contains(forbidden)) {
                forbidden = Utils.random(1, 9999);
            }
            forbiddenSet.add(forbidden);
            Main.outputInteger(ps, forbidden);
        }
        
        final String generatedInputPath = String.format("data/pc9/playingWithWheels/random%d.inp", testNumber);
        FileUtils.writeStringToFile(new File(generatedInputPath), out.toString("UTF-8"));
        out = new ByteArrayOutputStream();
        TaskReader taskReader = new TaskReader(new FileInputStream(generatedInputPath));
        try {
            Task task = null;
            while((task = taskReader.nextTask()) != null){
                long testStart = System.nanoTime();
//                new PrintStream(out).println(Main.solveAStar(task));
                assertEquals(Main.solveAStar(task), Main.solveBruteForce(task));
//                new PrintStream(out).println(Main.solveAStar(task));
//                new PrintStream(out).println(Main.solveBruteForce(task));
                time = System.nanoTime() - testStart;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(out.toString("UTF-8"));
        
        return time;
    }
}
